/*    

    bobbietalk - a visual programming environment for toy robotics

    Copyright (C) 2013  Roberto Tiella

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/
package bobbietalk.gui.blocks.parametrized;

import bobbietalk.gui.BobbietalkException;
import bobbietalk.gui.ProgrammingBlock;
import bobbietalk.gui.blocks.GenericMiddleBlock;
import bobbietalk.xsd.Palette;
import java.awt.Color;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

/**
 *
 * @author tiella
 */
public class BlockFactory {
    
    public static final String PALETTE_VERSION = "0.0.1";

    private Palette palette;
    private Map<String, Palette.BlockClass> blocks = new HashMap<>();

    public BlockFactory(File paletteXmlFile) throws BobbietalkException {
        try {
            
            JAXBContext jaxbContext = JAXBContext.newInstance(Palette.class);
            Unmarshaller unmar = jaxbContext.createUnmarshaller();

            palette = (Palette) unmar.unmarshal(new File("testdata/test1.xml"));
            
            if (palette.getVersion().equals(PALETTE_VERSION)) {

            for (Palette.BlockClass bc : palette.getBlockClass()) {
                blocks.put(bc.getType(), bc);
            }
            
            } else {
            
                throw new BobbietalkException("wrong version of palette file:"+paletteXmlFile+" expected:"+PALETTE_VERSION);
                
            }
            
        } catch (JAXBException ex) {
            throw new BobbietalkException("error reading palette file: "+paletteXmlFile, ex);
        }

    }

    public BlockFactory(InputStream resourceAsStream) throws JAXBException {

        JAXBContext jaxbContext = JAXBContext.newInstance(Palette.class);
        Unmarshaller unmar = jaxbContext.createUnmarshaller();

        palette = (Palette) unmar.unmarshal(resourceAsStream);

        for (Palette.BlockClass bc : palette.getBlockClass()) {
            blocks.put(bc.getType(), bc);
        }
    }

    public List<String> getTypes() {

        ArrayList<String> types = new ArrayList<>();

        for (Palette.BlockClass bc : palette.getBlockClass()) {
            types.add(bc.getType());
        }

        return types;

    }

    public Palette.BlockClass getBlockData(String type) {
        return blocks.get(type);
    }

    public ProgrammingBlock newInstance(String type) {

        Palette.BlockClass bc = blocks.get(type);

        GenericMiddleBlock b = new GenericMiddleBlock(bc.getType());

        b.setText(labelForCurrentLanguage(bc.getLabel()));
        b.setIconName(bc.getIcon());
        b.setTypeLabel(labelForCurrentLanguage(bc.getLabel()));
        b.setToolTipText(tooltipForCurrentLanguage(bc.getTooltip()));

        int colorCode = Integer.parseInt(bc.getBackgroundColor(), 16);

        b.setBackground(new Color(colorCode));
        b.setCodeTemplate("nxc", codeForProgrammingLanguage("nxc", bc.getCodeTemplate()));
        b.setCodeTemplate("bsh", codeForProgrammingLanguage("bsh", bc.getCodeTemplate()));


        for (Palette.BlockClass.Attributes.Attribute a : bc.getAttributes().getAttribute()) {

            TypeSpec ts = TypeSpec.buildFromXsdAttribute(a);

            String label = attributeLabelForCurrentLanguage(a.getLabel());

            b.addAttribute(a.getName(), ts, label, a.getDefaultValue(),
                    a.getUnits(), Boolean.parseBoolean(a.getEditable()),
                    Boolean.parseBoolean(a.getShowInLabel()));

        }


        return b;

    }

    private String labelForCurrentLanguage(List<Palette.BlockClass.Label> label) {

        final String country = getCountryCode();

        for (Palette.BlockClass.Label l : label) {


            if (l.getLang().equals(country)) {

                return l.getValue();

            }

        }

        throw new IllegalArgumentException("no label for current local:" + country);

    }

    
        private String tooltipForCurrentLanguage(List<Palette.BlockClass.Tooltip> tooltip) {

        final String country = getCountryCode();

        for (Palette.BlockClass.Tooltip l : tooltip) {


            if (l.getLang().equals(country)) {

                return l.getValue();

            }

        }

        throw new IllegalArgumentException("no label for current local:" + country);

    }
    
    private String codeForProgrammingLanguage(String pLang, List<Palette.BlockClass.CodeTemplate> codes) {

        for (Palette.BlockClass.CodeTemplate c : codes) {


            if (c.getPLang().equals(pLang)) {

                return c.getValue();

            }

        }

        throw new IllegalArgumentException("no code for specified language:" + pLang);

    }

    private String attributeLabelForCurrentLanguage(List<Palette.BlockClass.Attributes.Attribute.Label> label) {

        final String country = getCountryCode();

        for (Palette.BlockClass.Attributes.Attribute.Label l : label) {

            if (l.getLang().equals(country)) {

                return l.getValue();

            }

        }

        throw new IllegalArgumentException("no label for current local:" + country);
    }

    private String getCountryCode() throws MissingResourceException {
        return Locale.getDefault().getLanguage().toLowerCase();
    }

    public String getLocalizedBlockTypeName(String t) {

        Palette.BlockClass b = blocks.get(t);

        return labelForCurrentLanguage(b.getLabel());

    }
}
